package com.googlecode.stil.playground;

import android.hardware.SensorManager;
import android.util.Log;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.MassData;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.IOnAreaTouchListener;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.ITouchArea;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.shape.Shape;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class BlockBalanceActivity extends StilBaseGameActivity implements IAccelerationListener, IOnSceneTouchListener, IOnAreaTouchListener {

	private static final int CAMERA_WIDTH = 480;
	private static final int CAMERA_HEIGHT = 720;

	private ITextureRegion boxTextureRegion;
	private ITextureRegion ballTextureRegion;

	private static float BOX_WIDTH = 0;
	private static float BOX_HEIGHT = 0;

	private FixtureDef ballDef = PhysicsFactory.createFixtureDef(0.4f, 0.4f, 0.4f);
	private FixtureDef boxDef = PhysicsFactory.createFixtureDef(1f, 0.05f, 0.5f);
	private FixtureDef wallDef = PhysicsFactory.createFixtureDef(1.0f, 0.0f, 0.8f);

	private PhysicsWorld physics;
	private float gravityX, gravityY;

	private Shape currentBox;

	private Camera camera;

	private List<Shape> balls = new ArrayList<Shape>();

	@Override
	public EngineOptions onCreateEngineOptions() {
		camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.PORTRAIT_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
		engineOptions.getAudioOptions().setNeedsSound(true);
		return engineOptions;
	}

	@Override
	public void onCreateResources() {
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 500, 500, TextureOptions.BILINEAR);
		this.boxTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureAtlas, this, "crate.png", 0, 0);
		this.ballTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureAtlas, this, "soccer_ball.png", 257, 0);
		textureAtlas.load();

		BOX_WIDTH = this.boxTextureRegion.getWidth();
		BOX_HEIGHT = this.boxTextureRegion.getHeight();
	}

	@Override
	public Scene onCreateScene() {

		final Scene scene = new Scene();
		scene.setBackground(new Background(0.5f, 0.3f, 0.5f));
		scene.setOnAreaTouchListener(this);
		scene.setOnSceneTouchListener(this);

		initPhisics(scene);
		buildWalls(scene);

		return scene;
	}

	@Override
	public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

	@Override
	public void onResumeGame() {
		super.onResumeGame();

		this.enableAccelerationSensor(this);
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();

		this.disableAccelerationSensor();
	}

	private void buildWalls(Scene scene) {
		Rectangle roof = new Rectangle(0, 0, CAMERA_WIDTH, 50, getVertexBufferObjectManager());
		roof.setColor(1, 1, 1);
		PhysicsFactory.createBoxBody(physics, roof, BodyType.StaticBody, wallDef);
		scene.attachChild(roof);
		scene.registerTouchArea(roof);

		Rectangle floor = new Rectangle(0, CAMERA_HEIGHT - 5, CAMERA_WIDTH, 5, getVertexBufferObjectManager());
		floor.setColor(1, 1, 0);
		PhysicsFactory.createBoxBody(physics, floor, BodyType.StaticBody, wallDef);
		scene.attachChild(floor);

		Rectangle left = new Rectangle(0, 0, 5, CAMERA_HEIGHT, getVertexBufferObjectManager());
		left.setColor(0, 0, 1);
		PhysicsFactory.createBoxBody(physics, left, BodyType.StaticBody, wallDef);
		scene.attachChild(left);

		Rectangle right = new Rectangle(CAMERA_WIDTH - 5, 0, 5, CAMERA_HEIGHT, getVertexBufferObjectManager());
		right.setColor(0, 1, 1);
		PhysicsFactory.createBoxBody(physics, right, BodyType.StaticBody, wallDef);
		scene.attachChild(right);
	}

	private void initPhisics(Scene scene) {
		physics = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
		scene.registerUpdateHandler(physics);
	}

	private Shape addBall(Scene scene, float x, float y) {

		Random rnd = new Random();
		float choice = rnd.nextFloat();

		Shape shape;
		Body body;
		MassData mass;
		if (choice > 0.5) {
			shape = new Sprite(x, y, boxTextureRegion, getVertexBufferObjectManager());
			shape.setScale(0.5f);
			body = PhysicsFactory.createBoxBody(physics, shape, BodyType.DynamicBody, boxDef);
			mass = body.getMassData();
			mass.I = 0.05f;
			mass.mass = 2.0f;
		} else {
			shape = new Sprite(x, y, ballTextureRegion, getVertexBufferObjectManager());
			body = PhysicsFactory.createCircleBody(physics, shape, BodyType.DynamicBody, ballDef);
			mass = body.getMassData();
			mass.I = 0.05f;
			mass.mass = 0.45f;
		}

		body.setMassData(mass);
		shape.setUserData(body);
		physics.registerPhysicsConnector(new PhysicsConnector(shape, body, true, true));
		scene.attachChild(shape);
		balls.add(shape);

		return shape;
	}

	@Override
	public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) {
	}

	@Override
	public void onAccelerationChanged(AccelerationData pAccelerationData) {
		gravityX = pAccelerationData.getX();
		gravityY = SensorManager.GRAVITY_EARTH;

		final Vector2 gravity = Vector2Pool.obtain(gravityX, gravityY);
		physics.setGravity(gravity);
		Vector2Pool.recycle(gravity);
	}

	@Override
	public boolean onAreaTouched(TouchEvent pSceneTouchEvent, ITouchArea pTouchArea, float pTouchAreaLocalX, float pTouchAreaLocalY) {

		if (pSceneTouchEvent.isActionDown()) {
			Log.i("onAreaTouched", "isActionDown");
			currentBox = addBall(getEngine().getScene(), pSceneTouchEvent.getX() - BOX_WIDTH / 2, pSceneTouchEvent.getY() + 50);
			return true;
		}
		if (pSceneTouchEvent.isActionMove()) {
			Log.i("onAreaTouched", "isActionMove");
			if (this.currentBox != null) {
				Body boxBody = (Body) currentBox.getUserData();
				boxBody.setTransform(pSceneTouchEvent.getX() - BOX_WIDTH / 2, pSceneTouchEvent.getY() + 50, 0.5f);

				return true;
			}
		}
		if (pSceneTouchEvent.isActionUp()) {
			Log.i("onAreaTouched", "isActionUp");
		}
		return false;
	}

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		// if (pSceneTouchEvent.isActionDown()) {
		// addBall(pScene, pSceneTouchEvent.getX() - BALL_WIDTH / 2,
		// pSceneTouchEvent.getY() - BALL_HEIGHT / 2);
		// return true;
		// }
		return false;
	}
}